/**
 * Copyright (c) 2017 ShopJsp. All Rights Reserved.
 * ============================================================================
 * 版权所有 2011 - 今 北京华宇盈通科技有限公司，并保留所有权利。
 * ----------------------------------------------------------------------------
 * 提示：在未取得SHOPJSP商业授权之前，您不能将本软件应用于商业用途，否则SHOPJSP将保留追究的权力。
 * ----------------------------------------------------------------------------
 * 官方网站：http://www.shopjsp.com
 * ============================================================================
 * @author
 * @CreateTime 2017-3-31 13:57:45
 */
package com.hyyt.shopjsp.wxmg.publicNo.service.imp;

import com.hyyt.shopjsp.basic.pojo.BasicKeyBook;
import com.hyyt.shopjsp.product.pojo.ShopProductInfo;
import com.hyyt.shopjsp.product.service.IShopProductInfoService;
import com.hyyt.shopjsp.util.common.StringStaticKey;
import com.hyyt.shopjsp.util.common.Utils;
import com.hyyt.shopjsp.util.json.FastJsonUtils;
import com.hyyt.shopjsp.util.redis.util.RedisDataReadUtil;
import com.hyyt.shopjsp.util.wxpay.GetStreamParameter;
import com.hyyt.shopjsp.wxmg.basicInfo.pojo.WxGlobalReturnCode;
import com.hyyt.shopjsp.wxmg.fansMessage.pojo.*;
import com.hyyt.shopjsp.wxmg.fansMessage.service.*;
import com.hyyt.shopjsp.wxmg.publicNo.service.IWxOpenCommonService;
import com.hyyt.shopjsp.wxmg.publicNo.service.IWxPublicNoInfoService;
import com.hyyt.shopjsp.wxmg.util.*;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * WX_微信对外响应
 *
 * @author Robot 2017-03-31 13:57:45
 */
@Service
public class WxOpenCommonService implements IWxOpenCommonService {

    private static  final Logger logger = Logger.getLogger(IWxOpenCommonService.class);

    /**
     * 微信基础信息service
     */
    @Resource
    private IWxPublicNoInfoService wxPublicNoInfoService;

    /**
     * 微信文本消息service
     */
    @Resource
    private IWxTextMessageInfoService wxTextMessageInfoService;

    /**
     * 消息Service
     */
    @Resource
    private IWxImageMessageInfoService wxImageMessageInfoService;

    /**
     * 语音识别信息Service
     */
    @Resource
    private IWxVoiceIdentifyMessageInfoService wxVoiceIdentifyMessageInfoService;

    /**
     * 位置信息Service
     */
    @Resource
    private IWxLocationMessageInfoService wxLocationMessageInfoService;

    /**
     * 视频信息Service
     */
    @Resource
    private IWxVideoMessageInfoService wxVideoMessageInfoService;

    /**
     * 事件信息Service
     */
    @Resource
    private IWxEventMessageInfoService wxEventMessageInfoService;

    /**
     * 链接信息Service
     */
    @Resource
    private IWxUrlMessageInfoService wxUrlMessageInfoService;

    /**
     * 商品service
     */
    @Resource
    private IShopProductInfoService shopProductInfoService;

    /**
     * 保存WX_微信基础信息
     *
     * @param wxPublicNoInfo WX_微信基础信息
     * @return 保存后的WX_微信基础信息
     */
    @Override
    public Map<String,Object> wxTokenVerification(HttpServletRequest request, HttpServletResponse response, String echostr) {
        //项目设定对接微信的token
        String TOKEN = "";
        //获取微信公众号信息
        String wxPublicNoInfoStr = RedisDataReadUtil.getRedisValue(StringStaticKey.WX_PUBLIC_NO_INFO);
        Map<String,Object> wxPublicNoInfoMap = FastJsonUtils.stringToCollect(wxPublicNoInfoStr);
        String access_token = RedisDataReadUtil.getRedisValue(StringStaticKey.WX_ACCESS_TOKENS);
        if(Utils.objectIsNotEmpty(wxPublicNoInfoMap)){
            //获取微信公众号TOKEN
            if(Utils.stringIsNotEmpty( (String) wxPublicNoInfoMap.get("token"))){
                TOKEN = (String) wxPublicNoInfoMap.get("token");
            }
        }
        //微信响应工具类
        if (Utils.objectIsEmpty(echostr)) {
            //微信粉丝与公众号互动 后台自动接收回复消息和自动响应
            wxResponseMsg(request,response,access_token,wxPublicNoInfoMap);
        } else {
            //微信接口验证
            if (WxResponseInfo.checkSignature(request,response,TOKEN)) {
                WxResponseInfo.print(response,echostr);//向请求端发送返回数据
            } else {
                WxResponseInfo.print(response,"error");//向请求端发送返回数据
            }
        }
        Map<String,Object> params = new HashMap<>();
        params.put("access_token", access_token);// rows键 存放每页记录 list
        params.put("echostr", echostr);// rows键 存放每页记录 list
        return params;
    }

    /**
     * 微信粉丝与公众号互动
     * 后台自动接收回复消息和自动响应
     */
    private void wxResponseMsg(HttpServletRequest request,HttpServletResponse response,String access_token,Map<String,Object> wxPublicNoInfoMap) {
        String postStr = null;
        try {
           /**
            * voice 语音信息接收测试 // postStr = "<xml><ToUserName><![CDATA[gh_174103ae1111]]></ToUserName><FromUserName><![CDATA[o5HwDjz_M7GOZmVLX1erqtU4LYBQ]]></FromUserName><CreateTime>1410932939</CreateTime><MsgType><![CDATA[voice]]></MsgType><MediaId><![CDATA[HD9lVLQj1SdTwUVyzyesk8BV1RKkkGSumWPRXPCwLUi4_5Ha_faOcFp8Kybw1C56]]></MediaId><Format><![CDATA[amr]]></Format><MsgId>6059910829854162944</MsgId><Recognition><![CDATA[春纪]]></Recognition></xml>";
            * event 事件信息接收测试 // postStr = "<xml><ToUserName><![CDATA[gh_174103ae1111]]></ToUserName><FromUserName><![CDATA[o5HwDjz_M7GOZmVLX1erqtU4LYBQ]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[CLICK]]></Event><EventKey><![CDATA[zdhf]]></EventKey></xml>";
            * postStr = new String(postStr.getBytes(), "utf-8");
            * */
            //文本消息
            postStr = GetStreamParameter.readStreamParameter(request.getInputStream());
        } catch (Exception e) {
            logger.error(e);
        }
        logger.info("**** wxResponseMsg postStr对应的 xml文件是 = " + postStr);
        if (Utils.objectIsNotEmpty(postStr)) {
            Document document = null;
            try {
                document = DocumentHelper.parseText(postStr);
            } catch (Exception e) {
                logger.error(e);
            }
            if (null == document) {
                return;
            }else{
                //根据实际情况看是否需要回复空串，如果没有要被动回复的时候，回复空串
                //接受消息后返回空串或字符串表示已经接受到消息
                WxResponseInfo.print(response,"");
            }
            Element root = document.getRootElement();
            String msgType = root.elementText("MsgType");
            logger.info("** msgType 消息类型 = "+msgType);
            //1 文本消息，即粉丝用户之间给服务号发送的消息：(文本消息 ：text、图片消息：image、语言消息：voice、视频消息：video)
            if("text".equals(msgType)){
                logger.info("***********文本消息************");
                //1 封装成对象
                WxTextMessageInfo wxTextMessageInfo = (WxTextMessageInfo) WxXmlToJavaBean.postStrToBean(root, WxTextMessageInfo.class);
                //2 保存入库或者更新
                wxTextMessageInfoService.saveWxTextMessageInfo(wxTextMessageInfo,wxPublicNoInfoMap);
                //自动响应（回复）,此操作根据实际情况，看是否需要自动响应,以下为回复参数。
                //1 文本消息text、2图片消息image、3语音消息voice
                //4视频消息video、5音乐music、6图文消息news
                WxResponseInfo.wxAutoResponse(response,root,"text");
            }else if("image".equals(msgType)){//2图片消息
                logger.info("***********图片消息************");
                WxImageMessageInfo imageMessageInfo = (WxImageMessageInfo)WxXmlToJavaBean.postStrToBean(root, WxImageMessageInfo.class);
                wxImageMessageInfoService.saveWxImageMessageInfo(imageMessageInfo,wxPublicNoInfoMap);
                //code 保存消息
            }else if("voice".equals(msgType)){//3语言消息
                //语音识别消息使用的特有字段
                String recongnition = root.elementText("Recognition");
                logger.info("** Recongnition 语音识别结果 = " + recongnition);
                logger.info("***********语言消息************");
                WxVoiceIdentifyMessageInfo voiceIdentifyMessageInfo = (WxVoiceIdentifyMessageInfo)WxXmlToJavaBean.postStrToBean(root, WxVoiceIdentifyMessageInfo.class);
                wxVoiceIdentifyMessageInfoService.saveWxVoiceIdentifyMessageInfo(voiceIdentifyMessageInfo,wxPublicNoInfoMap);
                //如果语音识别结果不为空时，反馈用户结果
                if(Utils.objectIsNotEmpty(recongnition)){
                    //过滤语音识别中标点符号
                    String title = recongnition.replaceAll("[\\pP\\p{Punct}]", " ").trim();
                    List<WxArticle> articleList = this.createProductInfoArticleList(title);//得到图文数据集合
                    this.sendAutoMessage(voiceIdentifyMessageInfo,articleList,access_token);//调用自动回复图文消息
                }
                //code 保存消息
            }else if("video".equals(msgType)){//4视频消息
                logger.info("***********视频消息************");
                WxVideoMessageInfo videoMessageInfo = (WxVideoMessageInfo)WxXmlToJavaBean.postStrToBean(root, WxVideoMessageInfo.class);
                wxVideoMessageInfoService.saveWxVideoMessageInfo(videoMessageInfo,wxPublicNoInfoMap);
                //code 保存消息
            }else if("location".equals(msgType)){//5地理位置消息
                logger.info("***********地理位置消息************");
                WxLocationMessageInfo locationMessageInfo = (WxLocationMessageInfo)WxXmlToJavaBean.postStrToBean(root, WxLocationMessageInfo.class);
                wxLocationMessageInfoService.saveWxLocationMessageInfo(locationMessageInfo,wxPublicNoInfoMap);
                //code 保存消息
            }else if("link".equals(msgType)){//6链接消息
                logger.info("***********链接消息************");
                WxUrlMessageInfo urlMessageInfo = (WxUrlMessageInfo)WxXmlToJavaBean.postStrToBean(root, WxUrlMessageInfo.class);
                wxUrlMessageInfoService.saveWxUrlMessageInfo(urlMessageInfo,wxPublicNoInfoMap);
                //code 保存消息
            }else if("event".equals(msgType)){ //7事件消息（包括多种消息）
                /**
                 1 关注(Event:subscribe),保存事件消息，同时通过openId获取用户的详细信息保存用户信息
                 2 取消关注事件(Event:unsubscribe)
                 3 分为未关注和已经关注两种情况 扫描带参数二维码事件
                 未关注(EventKey不为空)
                 已经关注：(Event:SCAN)
                 4 上报地理位置事件(Event:LOCATION),用户每次点击进入时候更新用户的地理位置（也可以不更新）
                 5 自定义菜单事件:点击菜单拉取消息时的事件推送(Event:CLICK)
                 6 自定义菜单事件:点击菜单跳转链接时的事件推送(Event:VIEW)
                 7 事件信息，此处为MASSSENDJOBFINISH（高级群发结果）
                 * */
                String event = root.elementText("Event");
                logger.info("** event 事件类型 = "+event);
                if(Utils.objectIsNotEmpty(event)){
                    //目前只保存用户的“关注--subscrib”与“取消关注--unsubscribe”事件，其他事件不进行保存
                    WxEventMessageInfo eventMessageInfo=(WxEventMessageInfo) WxXmlToJavaBean.postStrToBean(root, WxEventMessageInfo.class);
                    List<BasicKeyBook> listKeyBook = RedisDataReadUtil.getBasicKeyBook("clickMenuReply");
                    String globalReturnCodeStr = RedisDataReadUtil.getRedisValue(StringStaticKey.WX_GLOBAL_RETURN_CODE);
                    List<WxGlobalReturnCode> globalReturnCodeList = FastJsonUtils.toList(globalReturnCodeStr, WxGlobalReturnCode.class);
                    wxEventMessageInfoService.saveWxEventMessageInfo(eventMessageInfo,wxPublicNoInfoMap);
                }
            }
        }
    }

    /**
     * 添加图文数据方法
     * @param title 微信语音识别结果
     * @return
     */
    private List<WxArticle> createProductInfoArticleList(String title) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("productFullName",title);
        //获取查询结果8条
        List<ShopProductInfo> productInfoList = shopProductInfoService.queryWxRecongnitionProductInfoList(params);
        List<WxArticle> articleList=new ArrayList<WxArticle>();//创建图文数据集合
        if(productInfoList!=null&&!"".equals(productInfoList)&&productInfoList.size()>0){
            int size=productInfoList.size();
            for(int i=0;i<size;i++){//循环放入图文集合中
                WxArticle wxArticle = new WxArticle();
                wxArticle.setTitle(productInfoList.get(i).getProductFullName());
                //从redis中获取手机微信项目路径
                String phoneBasePath = RedisDataReadUtil.getSysConfig("phoneBasePath");
                String uploadFileVisitRoot = RedisDataReadUtil.getSysConfig("uploadFileVisitRoot");
                wxArticle.setUrl(phoneBasePath + StringStaticKey.WX_PHONE_PRODUCT_INFO_PRODUCT_ID_URL + productInfoList.get(i).getProductId());
                wxArticle.setPicurl(uploadFileVisitRoot + productInfoList.get(i).getLogoImg());
                articleList.add(wxArticle);
            }
        }
        return articleList;
    }

    /**
     * 自动回复图文消息
     * 图文消息条数限制在10条以内，注意，如果图文数超过10，则将会无响应。
     * @param title 微信语音识别结果
     * @param wxVoiceIdentifyMessageInfo 粉丝用户发送的消息
     * @param articleList 为发送的数据不超过10条
     * @return
     */
    private void sendAutoMessage(WxVoiceIdentifyMessageInfo wxVoiceIdentifyMessageInfo, List<WxArticle> articleList, String access_token){
        //logger.info("回复图文消息--------"+wxVoiceIdentifyMessageInfo.getFromUserName());
        try {
            //图文消息条数限制在10条以内，注意，如果图文数超过10，则将会无响应。
            if(Utils.collectionIsNotEmpty(articleList)&&articleList.size()<=10&&articleList.size()>0){
                //1定义子map
                Map<String, Object> jsonSonMap = new HashMap<String, Object>();
                jsonSonMap.put("articles", articleList);
                //2定义主map
                Map<String, Object> jsonManMap = new HashMap<String, Object>();
                jsonManMap.put("touser", wxVoiceIdentifyMessageInfo.getFromUserName());
                jsonManMap.put("msgtype", "news");
                jsonManMap.put("news", jsonSonMap);
                //3格式化map
                JSONObject jo = JSONObject.fromObject(jsonManMap);
                String strJsonMap=jo.toString();
                //logger.info("********strJsonMap = "+strJsonMap);
                String sendMessageResult = WxBasicUtil.sendMessage(access_token, strJsonMap);
                //微信发送消息返回结果
                logger.info("******** 微信发送消息返回结果 WxOpenCommonService sendMessage = " + sendMessageResult);
            } else {
			    //logger.info("数据不能大于10条，请重新发送！此方法不能做判断处理返回，由开发人员再业务部分处理");
                Map<String, Object> jsonManMap = new HashMap<String, Object>();
                jsonManMap.put("touser", wxVoiceIdentifyMessageInfo.getFromUserName());
                jsonManMap.put("msgtype", "text");
                //定义子map
                Map<String, Object> jsonSonMap = new HashMap<String, Object>();
                String recognition = wxVoiceIdentifyMessageInfo.getRecognition();
                //过滤语音识别中标点符号
                recognition = recognition.replaceAll("[\\pP\\p{Punct}]", " ").trim();
                jsonSonMap.put("content","没有找到关于“"+recognition+"”的商品");
                jsonManMap.put("text", jsonSonMap);
                // 格式化map
                JSONObject jo = JSONObject.fromObject(jsonManMap);
                String strJsonMap = jo.toString();
			    //logger.info("strJsonMap="+strJsonMap);
                String sendMessageResult = WxBasicUtil.sendMessage(access_token, strJsonMap);
                //微信发送消息返回结果
                logger.info("******** 微信发送消息返回结果 WxOpenCommonService sendMessage = " + sendMessageResult);
            }
        } catch (Exception e) {
            logger.error(e);
        }
    }

}